package domein;

import java.io.*;
import java.net.*;
import java.util.Formatter;
import java.util.logging.Logger;

/**
 * 
 * @author rensbonnez
 * The TCP receiver.
 * 
 */

public class TCPReceiver extends Thread 
{
	public static Logger logger = Logger.getLogger("MyLog");
	private static final int bufferSize = Settings.getMaxFileSize();
	private static final int PORT = 8500;
	private File peerFileToDownload;
	private DownloadFile currentDownload;
	private PeerFile peerFile;
	
	private Socket downloadSocket;
	private Formatter formatter;
	private FileOutputStream out;
	private BufferedOutputStream bufferOut;
	private DataInputStream inputStream;
	
	public static final String STATUSES[] = {"Downloading", "Paused", "Complete", "Cancelled", "Error"};
    public static final int DOWNLOADING = 0;
    public static final int PAUSED = 1;
    public static final int COMPLETE = 2;
    public static final int CANCELLED = 3;
    public static final int ERROR = 4;

	public TCPReceiver(PeerFile peerFile, DownloadFile currentDownload)
	{
		try 
		{
	        setCurrentDownload(currentDownload);
	        setPeerFile(peerFile);
	        
			File downloadDir = new File(Settings.getDownloadDir());
			
			peerFileToDownload = new File(downloadDir, peerFile.getFileName());
			if(!peerFileToDownload.exists())
			{
				peerFileToDownload.createNewFile();
			}
		} 
		catch (FileNotFoundException e)
		{
			logger.info("File not found.");
		}
		catch (IOException e) 
		{
			logger.info("Dowload directory doesn't exists.");
		}
	}
	
	@Override
	public void run() 
	{	
		try 
		{
			logger.info("=============DOWNLOADING FILE=============");
			downloadSocket = new Socket(getPeerFile().getPeerIp(), PORT);
			
			formatter = new Formatter(downloadSocket.getOutputStream());
			formatter.format("%d\n", peerFile.getFileId());
			formatter.flush();
			
			//For downloading file
			out = new FileOutputStream(peerFileToDownload);
			bufferOut = new BufferedOutputStream(out);
			inputStream = new DataInputStream(downloadSocket.getInputStream());
			
			//change status of Download
			started();
			
			int read = 0;
			byte[] data = new byte[bufferSize];
			
			while ((read = inputStream.read(data)) != -1) 
			{
				bufferOut.write(data, 0, read);
				getCurrentDownload().setDownloadProgression(read);
			}
			
			logger.info("File is succesfully downloaded");
			complete();
			
			bufferOut.flush();
			bufferOut.close();
			out.close();
			inputStream.close();
			downloadSocket.close();
		} 
		catch (UnknownHostException e)
		{
			error();
			logger.info("Host not found!");
			peerFileToDownload.delete();
			
			try
			{
				out.close();
				bufferOut.close();
				inputStream.close();
				downloadSocket.close();
			}
			catch (IOException e1)
			{
				logger.info("Failed to close connection");
			}
		}
		catch (FileNotFoundException e)
		{
			error();
			logger.info("File cannot download, file not found or directory doesn't exist.");
			
			try
			{
				downloadSocket.close();
			}
			catch (IOException e1)
			{
				logger.info("Failed to close connection");
			}
		}
		catch (SocketException e)
		{
			error();
			logger.info("A fault occured in the socket. Probably the server disconnected while uploading data.");
			peerFileToDownload.delete();
			
			try
			{
				out.close();
				bufferOut.close();
				inputStream.close();
			}
			catch (IOException e1)
			{
				logger.info("Failed to close connection");
			}
		}
		catch (IOException e) 
		{
			error();
			peerFileToDownload.delete();
			e.printStackTrace();
			
			try
			{
				out.close();
				bufferOut.close();
				inputStream.close();
				downloadSocket.close();
			}
			catch (IOException e1)
			{
				logger.info("Failed to close connections");
			}
		}
	}
	
	public void started() 
    {
    	getCurrentDownload().setDownloadStatus(STATUSES[0]);
    }
    
    public void pause() 
    {
    	getCurrentDownload().setDownloadStatus(STATUSES[1]);
    }
    
    public void resumed() 
    {
    	getCurrentDownload().setDownloadStatus(STATUSES[0]);
    }
    
    public void complete()
    {
    	getCurrentDownload().setDownloadStatus(STATUSES[2]);
    }
    
    public void cancel() 
    {
    	getCurrentDownload().setDownloadStatus(STATUSES[3]);
    }
    
    public void error() 
    {
    	getCurrentDownload().setDownloadStatus(STATUSES[4]);
    	PeerController.getInstance().fileDidNotDownlaodSuccessfull(getPeerFile());
    }
    
	/**
	 * Getters and Setters
	 */

	public File getPeerFileToDownload() {
		return peerFileToDownload;
	}

	public void setPeerFileToDownload(File peerFileToDownload) {
		this.peerFileToDownload = peerFileToDownload;
	}

	public DownloadFile getCurrentDownload() {
		return currentDownload;
	}

	public void setCurrentDownload(DownloadFile currentDownload) {
		this.currentDownload = currentDownload;
	}

	public PeerFile getPeerFile() {
		return peerFile;
	}

	public void setPeerFile(PeerFile peerFile) {
		this.peerFile = peerFile;
	}

	public Formatter getFormatter() {
		return formatter;
	}

	public void setFormatter(Formatter formatter) {
		this.formatter = formatter;
	}
}